package ru.compscicenter.uno.wizard;

import ru.compscicenter.uno.controller.ClientController;
import ru.compscicenter.uno.controller.ServerController;
import ru.compscicenter.uno.log.Logger;
import ru.compscicenter.uno.model.Rules;
import ru.compscicenter.uno.model.StringRepresentation;
import ru.compscicenter.uno.view.SwingViewer;

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * This class is responsible for reacting to events generated by pushing any of the
 * three buttons, 'Next', 'Previous', and 'Cancel.' Based on what button is pressed,
 * the controller will update the model to show a new panel and reset the state of
 * the buttons as necessary.
 */
public class WizardController implements ActionListener {
    
    private Wizard wizard;
    
    /**
     * This constructor accepts a reference to the Wizard component that created it,
     * which it uses to update the button components and access the WizardModel.
     * @param w A callback to the Wizard component that created this controller.
     */    
    public WizardController(Wizard w) {
        wizard = w;
    }

    /**
     * Calling method for the action listener interface. This class listens for actions
     * performed by the buttons in the Wizard class, and calls methods below to determine
     * the correct course of action.
     * @param evt The ActionEvent that occurred.
     */    
    public void actionPerformed(java.awt.event.ActionEvent evt) {
        
        if (evt.getActionCommand().equals(Wizard.CANCEL_BUTTON_ACTION_COMMAND))
            cancelButtonPressed();
        else if (evt.getActionCommand().equals(Wizard.BACK_BUTTON_ACTION_COMMAND))
            backButtonPressed();
        else if (evt.getActionCommand().equals(Wizard.NEXT_BUTTON_ACTION_COMMAND))
            nextButtonPressed();
    }
    
    
    
    private void cancelButtonPressed() {
        WizardModel model = wizard.getModel();
        WizardPanelDescriptor descriptor = model.getCurrentPanelDescriptor();
        if (descriptor.getPanelDescriptorIdentifier().equals(Panel3ClientRulesDescriptor.IDENTIFIER) ||
                descriptor.getPanelDescriptorIdentifier().equals(Panel4ClientWaitDescriptor.IDENTIFIER)) {
            try {
                wizard.gameSettings.clientController.disconnect();
                wizard.gameSettings.clientController.stopTCPClient();
            } catch (IOException e) {
                Panel2Client.showMessage("Some shit happened while disconnecting from the server");
                Logger.write("Some shit happened while disconnecting from the server" + e.toString(), Logger.Mode.ERROR);
                //wizard.gameSettings.clientController = null;
            }
        }
        System.exit(0);
        wizard.close(Wizard.CANCEL_RETURN_CODE);
    }

    private void nextButtonPressed() {
        Logger.write("WIZARD: next button pressed", Logger.Mode.ACTION);
        WizardModel model = wizard.getModel();
        WizardPanelDescriptor descriptor = model.getCurrentPanelDescriptor();
        
        //  If it is a finishable panel, close down the dialog. Otherwise,
        //  get the ID that the current panel identifies as the next panel,
        //  and display it.
        
        Object nextPanelDescriptor = descriptor.getNextPanelDescriptor();
        
        if (nextPanelDescriptor instanceof WizardPanelDescriptor.FinishIdentifier) {
            if (descriptor.getPanelDescriptorIdentifier().equals(Panel3ServerWaitDescriptor.IDENTIFIER)) {
                wizard.gameSettings.serverController.stopGameBroadcast();
                wizard.gameSettings.serverController.initPlayers();
                wizard.gameSettings.serverController.startRound();
               // wizard.gameSettings.view = new SwingViewer(wizard.gameSettings.clientController);
               // wizard.gameSettings.view.run();
            }
            wizard.close(Wizard.FINISH_RETURN_CODE);
            Logger.write("WIZARD: closed", Logger.Mode.ACTION);
        } else {        
            if (descriptor.getPanelDescriptorIdentifier().equals(Panel2ClientDescriptor.IDENTIFIER)) {
                wizard.gameSettings.clientController = new ClientController(true, false);
                try {
                    wizard.gameSettings.clientController.connect(wizard.gameSettings.address, wizard.gameSettings.name);
                    String respond = wizard.gameSettings.clientController.getRespond();
                    if (respond.startsWith("Connected")) {                                                
                        String[] spl = respond.split(":");
                        Panel3ClientRules.setRules(StringRepresentation.rulesFromStringRepresentation(spl[1]));
                        wizard.gameSettings.clientController.runTCPClient();
                    }
                } catch (Exception e) {
                    Panel2Client.showMessage("Failed to connect to the selected server!!! Try another one!!!");
                    Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
                    return;
                }
            } else if (descriptor.getPanelDescriptorIdentifier().equals(Panel1Descriptor.IDENTIFIER) && wizard.gameSettings.mode.equals(Panel1.IS_SERVER)) {
                if (wizard.gameSettings.serverController != null) {
                    wizard.gameSettings.serverController.stopServer();
                    wizard.gameSettings.serverController.stopGameBroadcast();
                }

                if (wizard.gameSettings.clientController != null) {
                    wizard.gameSettings.clientController.stopTCPClient();
                }

                wizard.gameSettings.serverController = new ServerController(true, wizard.gameSettings.name);
                wizard.gameSettings.clientController = new ClientController(false, true);
                try {
                    wizard.gameSettings.clientController.connect(wizard.gameSettings.networkInterface + ":" + wizard.gameSettings.serverController.getPort(), wizard.gameSettings.name);
                    String respond = wizard.gameSettings.clientController.getRespond();
                    if (respond.startsWith("Connected")) {
                        String[] spl = respond.split(":");
                        Panel3ClientRules.setRules(StringRepresentation.rulesFromStringRepresentation(spl[1]));
                        wizard.gameSettings.clientController.runTCPClient();
                    }
                } catch (IOException e) {
                    Panel2Client.showMessage("Failed to connect to the selected server!!! Try another one!!!");
                    Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
                    return;
                }
            } else if (descriptor.getPanelDescriptorIdentifier().equals(Panel1Descriptor.IDENTIFIER) && wizard.gameSettings.mode.equals(Panel1.IS_CLIENT)) {
                if (wizard.gameSettings.serverController != null) {
                    wizard.gameSettings.serverController.stopServer();
                    wizard.gameSettings.serverController.stopGameBroadcast();
                }

                wizard.gameSettings.clientController = new ClientController(false, true);

                wizard.gameSettings.panel2client.updateAvailableServers();
            } else if (descriptor.getPanelDescriptorIdentifier().equals(Panel2ServerRulesDescriptor.IDENTIFIER)) {
                if (wizard.gameSettings.serverController.isStopped()) {
                    wizard.gameSettings.serverController.reStartServer();
                    wizard.gameSettings.clientController.stopTCPClient();
                    wizard.gameSettings.clientController = new ClientController(true, false);
                    try {
                        wizard.gameSettings.clientController.connect(wizard.gameSettings.networkInterface + ":" + wizard.gameSettings.serverController.getPort(), wizard.gameSettings.name);
                        String respond = wizard.gameSettings.clientController.getRespond();
                        if (respond.startsWith("Connected")) {
                            String[] spl = respond.split(":");
                            Panel3ClientRules.setRules(StringRepresentation.rulesFromStringRepresentation(spl[1]));
                            wizard.gameSettings.clientController.runTCPClient();
                        }
                    } catch (IOException e) {
                        Panel2Client.showMessage("Failed to connect to the selected server!!! Try another one!!!");
                        Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
                        return;
                    }
                }
                wizard.gameSettings.serverController.startGameBroadcast(wizard.gameSettings.networkInterface);
                Panel3ServerWait.myIPtext.setText(wizard.gameSettings.networkInterface + ":" + wizard.gameSettings.serverController.getPort());
            }
            wizard.setCurrentPanel(nextPanelDescriptor);
        }
    }

    private void backButtonPressed() {
        Logger.write("WIZARD: back button pressed", Logger.Mode.ACTION);
        WizardModel model = wizard.getModel();
        WizardPanelDescriptor descriptor = model.getCurrentPanelDescriptor();
 
        //  Get the descriptor that the current panel identifies as the previous
        //  panel, and display it.
        
        Object backPanelDescriptor = descriptor.getBackPanelDescriptor();        
        if (descriptor.getPanelDescriptorIdentifier().equals(Panel3ClientRulesDescriptor.IDENTIFIER)) {
            try {
                wizard.gameSettings.clientController.disconnect();
                //wizard.gameSettings.clientController = null;
            } catch (IOException e) {
                Panel2Client.showMessage("Some shit happened while disconnecting from the server");
                Logger.write("Some shit happened while disconnecting from the server" + e.toString(), Logger.Mode.ERROR);
                //wizard.gameSettings.clientController = null;
                wizard.setCurrentPanel(backPanelDescriptor);
            }
        } else if (descriptor.getPanelDescriptorIdentifier().equals(Panel3ServerWaitDescriptor.IDENTIFIER)) {
            wizard.gameSettings.serverController.stopServer();
            wizard.gameSettings.serverController.stopGameBroadcast();
//            wizard.gameSettings.serverController.stopServer();
//            wizard.gameSettings.serverController = new ServerController(true, wizard.gameSettings.name);
//            wizard.gameSettings.clientController = new ClientController(false, true);
//            try {
//                wizard.gameSettings.clientController.connect(wizard.gameSettings.networkInterface + ":" + wizard.gameSettings.serverController.getPort(), wizard.gameSettings.name);
//                String respond = wizard.gameSettings.clientController.getRespond();
//                if (respond.startsWith("Connected")) {
//                    String[] spl = respond.split(":");
//                    Panel3ClientRules.setRules(StringRepresentation.rulesFromStringRepresentation(spl[1]));
//                    wizard.gameSettings.clientController.runTCPClient();
//                }
//            } catch (IOException e) {
//                Panel2Client.showMessage("Failed to connect to the selected server!!! Try another one!!!");
//                Logger.write("Failed to connect to the selected server: " + e.toString(), Logger.Mode.ERROR);
//                return;
//            }
        }
        wizard.setCurrentPanel(backPanelDescriptor);
    }

    
    void resetButtonsToPanelRules() {
    
        //  Reset the buttons to support the original panel rules,
        //  including whether the next or back buttons are enabled or
        //  disabled, or if the panel is finishable.
        
        WizardModel model = wizard.getModel();
        WizardPanelDescriptor descriptor = model.getCurrentPanelDescriptor();
        
        model.setCancelButtonText(Wizard.CANCEL_TEXT);
        model.setCancelButtonIcon(Wizard.CANCEL_ICON);
        
        //  If the panel in question has another panel behind it, enable
        //  the back button. Otherwise, disable it.
        
        model.setBackButtonText(Wizard.BACK_TEXT);
        model.setBackButtonIcon(Wizard.BACK_ICON);
        
        if (descriptor.getBackPanelDescriptor() != null)
            model.setBackButtonEnabled(Boolean.TRUE);
        else
            model.setBackButtonEnabled(Boolean.FALSE);

        //  If the panel in question has one or more panels in front of it,
        //  enable the next button. Otherwise, disable it.
 
        if (descriptor.getNextPanelDescriptor() != null)
            model.setNextFinishButtonEnabled(Boolean.TRUE);
        else
            model.setNextFinishButtonEnabled(Boolean.FALSE);
 
        //  If the panel in question is the last panel in the series, change
        //  the Next button to Finish. Otherwise, set the text back to Next.
        
        if (descriptor.getNextPanelDescriptor() instanceof WizardPanelDescriptor.FinishIdentifier) {
            model.setNextFinishButtonText(Wizard.FINISH_TEXT);
            model.setNextFinishButtonIcon(Wizard.FINISH_ICON);
        } else {
            model.setNextFinishButtonText(Wizard.NEXT_TEXT);
            model.setNextFinishButtonIcon(Wizard.NEXT_ICON);
        }


    }
}
